#ifndef HOPFIELD_H_
#define HOPFIELD_H_

#include "Pattern.h"
#include <ctime>

#define CONVERGENCE_FACTOR  20

/*
 * =====================================================================================
 *        Class:  Hopfield
 *  Description:  Classe que representa uma rede Hopfield
 * =====================================================================================
 */
class Hopfield
{

public:

    /*-----------------------------------------------------------------------------
     *  Construtor
     *-----------------------------------------------------------------------------*/
    Hopfield();

    /*-----------------------------------------------------------------------------
     *  Destrutor
     *-----------------------------------------------------------------------------*/
    virtual ~Hopfield();

    /*-----------------------------------------------------------------------------
     *  Treina a rede passando uma memória de padrões
     *-----------------------------------------------------------------------------*/
    void train(MemoryPtr mem);

    /*-----------------------------------------------------------------------------
     *  Inicializa o teste
     *-----------------------------------------------------------------------------*/
    void initTest(MemoryPtr mem, uint which, PatternPtr &pattern);

    /*-----------------------------------------------------------------------------
     *  Testa a rede passando uma memória de padrões
     *-----------------------------------------------------------------------------*/
    bool test(PatternPtr pattern);

    /*-----------------------------------------------------------------------------
     *  Inicializa os índices aleatórios
     *-----------------------------------------------------------------------------*/
    void initRandIndex();

    /*-----------------------------------------------------------------------------
     *  Randomiza os índices
     *-----------------------------------------------------------------------------*/
    void randomizeIndex();

    /*-----------------------------------------------------------------------------
     *  Retorna o comprimento
     *-----------------------------------------------------------------------------*/
    uint size() { return weight->cols; }

    /*-----------------------------------------------------------------------------
     *  Retorna o peso
     *-----------------------------------------------------------------------------*/
    double& at(uint i, uint j) { return weight->at(i, j); }

private:

    /*-----------------------------------------------------------------------------
     *  Quantidade de neurônios
     *-----------------------------------------------------------------------------*/
    uint nNeurons;

    /*-----------------------------------------------------------------------------
     *  Índices aleatórios
     *-----------------------------------------------------------------------------*/
    uint* randIndex;

    /*-----------------------------------------------------------------------------
     *  Número de iterações para verificar convergência
     *-----------------------------------------------------------------------------*/
    uint stableIterations;

    /*-----------------------------------------------------------------------------
     *  Matriz de pesos dos neurônios
     *-----------------------------------------------------------------------------*/
    MatrixPtr weight;

};

/*-----------------------------------------------------------------------------
 *  Ponteiro
 *-----------------------------------------------------------------------------*/
typedef shared_ptr<Hopfield> HopfieldPtr;

#endif /* HOPFIELD_H_ */
